home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 43
/
Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso
/
-serious-
/
archivers
/
checkx
/
sources
/
checkx.c
next >
Wrap
C/C++ Source or Header
|
1999-06-14
|
53KB
|
1,768 lines
#define NAME "CheckX"
#define REVISION "57"
#define DISTRIBUTION "(Freeware) "
/*
When someone uses the here shown methods for own programs, he has to
contact me first and always to mention me in his program documentation!
This program scans for crunched, linked files and archived files. It
decrunches them and saves the result files to another directory-tree.
The scanning routines are recursiv and thus check really all stuff. Linked
files are saved with .1, .2, ... additions.
The main purpose it was written for is to scan for crunched files and to
test the decrunch routines. So the logging may take some more time, but is
very stable, as the last log-entry is always the file which possibly
crashed the machine.
Address crunched programs are decrunched as well, but not saved. Use
xfdDecrunch or xfdDecrunchAddr to generate decrunched executable files
of this type (with correct header information).
CheckX cannot scan files, which are read-protected. You get CheckX error 4
as result in that case. Unprotect files and scan again when you want.
NOTE: SaveDir must exist already, only sub-dirs are created.
The program must be compiled and linked without startup-code. You can set
the pure file protection bit and make it resident, because it is multi-
reentrant (no global variables, except library bases).
This means it can be called multiple times as well, but this is not
recommended, as said above CheckX needs lots of memory.
Disk archives are handled this way:
They are unarchived to RD0: in depth1, to RD1: in depth2 (when archive is
in RD0:) and to RD2: in depth3, ....
NOTE: accessing RD0:, RD1 or RD2: during this time may produce errors.
This includes starting CheckX twice, when scanning disk archives. For high
density archives the archive names are RH1:, RH2:, ...
Splitted DMS-Archives may produce strange errors, but can be checked
correctly, when the two parts are directly after another (e.g. no other
track archive is between them). In this case the first file shows some
XPKCERR_READWRITE and the second one the correct stuff.
Crypted archives are not supported yet (e.g. asking for password).
*/
/* Programmheader
Name: CheckX
Author: SDI
Distribution: Freeware
Description: scans and decrunches crunched files with xfd
Compileropts: -
Linkeropts: -l xpkmaster xadmaster amiga -gsi
1.0 14.12.96 : first Version
1.1 28.12.96 : moved PassRequest into xpkmaster.library
1.2 12.02.97 : now also decrunches Exe-Files
1.3 15.06.97 : added length output as test
1.4 21.11.97 : renamed from Decrunch, got really new program
1.5 22.11.97 : bug-fixes
1.6 29.11.97 : added unarchiving feature
1.7 30.11.97 : bug-fixes
1.8 06.12.97 : xpkmaster.library now only required with ASKPWD option
1.9 07.12.97 : Added archive copy for weird archive names, better error
codes
1.10 08.12.97 : fixed error codes a bit
1.11 11.12.97 : disabled DOS requests, added Zip-Archives, added TaskID
to temporary filenames
1.12 12.12.97 : added Arc, ZOO and LhASFX archives
1.13 13.12.97 : fixed Arc recognition
1.14 19.12.97 : deletes copied arc before scan
1.15 22.12.97 : crunched archives are unarchived correctly now
1.16 02.01.98 : opens dos.library itself, no startup-code required
1.17 23.01.98 : added disk crunchers
1.18 24.01.98 : some fixes
1.19 01.02.98 : little bug-fix in argument-option use
1.20 06.02.98 : better error output, added automount
1.21 08.02.98 : little bug-fix
1.22 10.02.98 : fixed archive copy conditions, added PRINTALL
1.23 12.02.98 : fixed help text, bug fixes with unlinking and FreeMem
1.24 13.02.98 : added unstripping
1.25 04.03.98 : added PRINTEXEC
1.26 13.03.98 : added high density DMS support
1.27 19.03.98 : added LOUD keyword
1.28 23.03.98 : RDx no longer depends on archive depth, but on dddepth
1.29 10.04.98 : bug fixes
1.30 26.04.98 : bug fixes
1.31 09.05.98 : now uses no longer adress 4 for SysBase
1.32 31.05.98 : better output
1.33 04.06.98 : added HEADER addition for address files
1.34 08.08.98 : bug fix with SAVE
1.35 24.09.98 : added xvs.library virus checks
1.36 18.10.98 : xvs is opened global and only once
1.37 30.10.98 : renamed from CheckXFD
1.38 11.11.98 : fixed format drive bug using a delay and an error report
1.39 14.11.98 : format error with AUTOMOUNT removed
1.40 16.11.98 : removed HEADER addition stuff
1.41 18.11.98 : better RDx: access and mount
1.42 23.11.98 : fixed bug with hunk stripping
1.43 29.12.98 : now prints an error, when virus detection is turned off,
added time calculation and output
1.44 31.12.98 : little bug fix
1.45 06.02.99 : bug fixes, added xadmaster.library stuff, removed LOUD
and internal DMS call
1.46 09.02.99 : removed internal LZX call
1.47 11.02.99 : now uses assembler startcode allocating a bigger stack
1.48 14.02.99 : bug-fixes for nocylinder archivers (PackDev)
1.49 16.02.99 : fixed strip option (don't know, where the error was :-)
1.50 21.02.99 : removed internal Zoom call and disk-archiver stuff
1.51 22.02.99 : fixed archiver call for remaining non-XAD archivers, added
empty file check
1.52 23.02.99 : fixed StartCode return value
1.53 24.02.99 : forgot empty check for archived files
1.54 08.03.99 : old archiver calling did not work, when file was XAD
unarchived
1.55 26.03.99 : prints error, when logfile cannot be created
1.56 30.03.99 : added bootblock scanning for unarchived disks
1.57 16.05.99 : bug fix with unlinked file save
*/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/xfdmaster.h>
#include <proto/xadmaster.h>
#include <proto/xpkmaster.h>
#include <proto/intuition.h>
#include <proto/xvs.h>
#include <libraries/xfdmaster.h>
#include <dos/dostags.h>
#include <dos/doshunks.h>
#include <dos/filehandler.h>
#include <exec/memory.h>
#include "SDI_defines.h" /* make version string */
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#define PARAM "FROM,LOG,SAVE/K,ALL/S,ASKPWD/S,AUTOMOUNT/S,PRINTALL/S," \
"PRINTEXEC/S," \
"NODECRUNCH/S,NOUNLINK/S,NOUNARCHIVE/S,NOUNTRACK/S," \
"NOTRACKCUT/S,NOSTRIP/S,NOVIRUS/S"
#ifdef __SASC
#define XpkBase xpkbase
#define ASSIGN_XPK
#define IntuitionBase intuitionbase
#define ASSIGN_INT
#else
struct Library * XpkBase = 0;
struct IntuitionBase *IntuitionBase = 0;
#define ASSIGN_XPK XpkBase = xpkbase;
#define ASSIGN_INT IntuitionBase = intuitionbase;
#endif
struct xfdMasterBase * xfdMasterBase = 0;
struct DosLibrary * DOSBase = 0;
struct ExecBase * SysBase = 0;
struct xvsBase * xvsBase = 0;
struct xadMasterBase * xadMasterBase = 0;
struct Args {
STRPTR from;
STRPTR log;
STRPTR save;
ULONG all;
ULONG askpwd;
ULONG automount;
ULONG printall;
ULONG printexec;
ULONG nodecrunch;
ULONG nounlink;
ULONG nounarchive;
ULONG nountrack;
ULONG notrackcut;
ULONG nostrip;
ULONG novirus;
};
struct CrunchMemList {
struct CrunchMemList * cml_Next;
APTR cml_MemoryRegion;
ULONG cml_MemorySize;
};
#define CHECKXFLAG_SAVE (1<< 0)
#define CHECKXFLAG_ALL (1<< 1)
#define CHECKXFLAG_ASKPWD (1<< 2)
#define CHECKXFLAG_AUTOMOUNT (1<< 3)
#define CHECKXFLAG_PRINTALL (1<< 4)
#define CHECKXFLAG_PRINTEXEC (1<< 5)
#define CHECKXFLAG_NODECRUNCH (1<< 6)
#define CHECKXFLAG_NOUNLINK (1<< 7)
#define CHECKXFLAG_NOUNARCHIVE (1<< 8)
#define CHECKXFLAG_NOUNTRACK (1<< 9)
#define CHECKXFLAG_NOTRACKCUT (1<<10)
#define CHECKXFLAG_NOSTRIP (1<<11)
#define CHECKXFLAG_XVSLIB (1<<15)
#define CHECKXFLAG_XADLIB (1<<16)
#define CHKXCALLFLAGS (CHECKXFLAG_SAVE|CHECKXFLAG_ALL| \
CHECKXFLAG_ASKPWD|CHECKXFLAG_AUTOMOUNT| \
CHECKXFLAG_PRINTALL|CHECKXFLAG_PRINTEXEC| \
CHECKXFLAG_NODECRUNCH|CHECKXFLAG_NOUNLINK| \
CHECKXFLAG_NOUNARCHIVE|CHECKXFLAG_NOUNTRACK| \
CHECKXFLAG_NOTRACKCUT|CHECKXFLAG_NOSTRIP| \
CHECKXFLAG_XVSLIB|CHECKXFLAG_XADLIB)
#define CHKXSAVEFLAGS (CHECKXFLAG_LINKED|CHECKXFLAG_CRUNCHED| \
CHECKXFLAG_STRIPPED)
#define CHECKXFLAG_NAMEPRINTED (1<<20)
#define CHECKXFLAG_CRUNCHED (1<<21)
#define CHECKXFLAG_LINKED (1<<22)
#define CHECKXFLAG_ADDRESS (1<<23)
#define CHECKXFLAG_NOFREEMEM (1<<24)
#define CHECKXFLAG_STRIPPED (1<<25)
#define CHECKXFLAG_HIGHDENSITY (1<<26)
#define CHECKXFLAG_FILEARCHIVED (1<<27)
#define CHECKXFLAG_DISKARCHIVED (1<<28)
#define XADERR_OFFSET 0x100
#define XFDERR_OFFSET 0x200
#define CHKXERR_NOMEMORY 1
#define CHKXERR_EXAMINEERR 2
#define CHKXERR_OPENERR 3
#define CHKXERR_READWRITE 4
#define CHKXERR_SCANERR 5
#define CHKXERR_BREAK 6
#define CHKXERR_OPENDIR 7
#define CHKXERR_NORAD 8
#define CHKXERR_NODOS 9 /* not a dos disk */
#define CHKXERR_RESOURCE 10
#define CHKXERR_NOVIRUS 11
#define CHKXERR_EMPTY 12
#define CHKXERR_NOBOOTVIRUS 13
struct FileData {
struct CrunchMemList * fd_MemList;
STRPTR fd_Name;
ULONG fd_LogFileFH;
ULONG fd_SaveDirL;
ULONG fd_Flags;
ULONG fd_NumVirus;
BYTE fd_RecurseDepth;
UBYTE fd_LinkNum;
UBYTE fd_ArchiveDepth;
UBYTE fd_DDDepth;
UBYTE fd_HDDepth;
};
LONG DoDirectoryScan(STRPTR, STRPTR, struct FileData *);
LONG DoFileOpen(struct FileData *);
void DoMount(ULONG, ULONG);
BPTR GetRad(struct FileData *, STRPTR);
LONG DoGetVirus(struct FileData *, APTR, ULONG);
LONG DoFileUnArchive(struct FileData *, APTR, ULONG);
LONG DoFileUnLink(struct FileData *, APTR, ULONG);
LONG DoFileUnCrunch(struct FileData *, APTR, ULONG);
LONG DoFileStrip(struct FileData *, APTR, ULONG);
void PrintCHKXFile(struct FileData *);
void PrintCHKXErr(struct FileData *, LONG);
void PrintCHKXTxt(struct FileData *, STRPTR, ...);
LONG AddCrunchMemList(struct FileData *, APTR, ULONG);
void FreeCrunchMemList(struct FileData *, APTR);
LONG SaveUncrFile(struct FileData *, APTR, ULONG);
ULONG OpenParentDir(struct FileData *);
ULONG OpenNewDir(struct FileData *, STRPTR);
/* All memory regions must be in mem list. All unneeded memory must be freed
as fast as possible (after unlinking, decrunching), as well as the
MemoryList structure.
The program has a loop like scan routine system, which is called for
every file:
A) Scan files, directories and sub directories and call following for
every file:
1) Check for viruses.
2) Test if it is an archive. When yes decrunch and start with point A.
3) Test if file is linked. When yes unlink and call point 1 for both
parts.
4) Test if file is crunched. When yes, decrunch and start again with
point 1.
5) Try stripping useless stuff. When succesful start with point 1 again.
6) Possibly save file (with SAVE option) or end loop here.
*/
/* main routine, do argument parsing */
LONG start(void)
{
LONG error = RETURN_FAIL;
struct DosLibrary *dosbase;
struct Process *task;
SysBase = (*((struct ExecBase **) 4));
/* test for WB and reply startup-message */
if(!(task = (struct Process *) FindTask(0))->pr_CLI)
{
WaitPort(&task->pr_MsgPort);
Forbid();
ReplyMsg(GetMsg(&task->pr_MsgPort));
return RETURN_FAIL;
}
if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
{
struct xfdMasterBase *xfdmasterbase;
DOSBase = dosbase;
if((xfdmasterbase = (struct xfdMasterBase *)
OpenLibrary("xfdmaster.library", 37)))
{
struct Args Args;
struct RDArgs *rda;
xfdMasterBase = xfdmasterbase;
memset(&Args, 0, sizeof(struct Args));
if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
{
rda->RDA_ExtHelp =
"FROM source file or directory - may contain patterns\n"
"LOG log file name\n"
"SAVE directory, where decrunched files are saved\n"
"ALL scan deep into directories\n"
"ASKPWD ask for password when needed (needs xpkmaster.library)\n"
"PRINTALL print all filenames\n"
"PRINTEXEC print names of all executable files\n"
"AUTOMOUNT automatically mount RDx: device when needed\n"
"NODECRUNCH do not decrunch files with xfdmaster\n"
"NOUNLINK do not unlink files with xfdmaster\n"
"NOUNARCHIVE do not call archiver for unarchiving file archives\n"
"NOUNTRACK do not call archiver for unarchiving track archives\n"
"NOTRACKCUT do not call archiver for partially track archives\n"
"NOSTRIP do not strip useless hunks\n"
"NOVIRUS do not scan with xvs.library for viruses\n";
if(ReadArgs(PARAM, (LONG *) &Args, rda))
{
ULONG flags = 0, log = 0;
struct xvsBase *xvsbase = 0;
struct xadMasterBase *xadmasterbase = 0;
if(!Args.from) Args.from = "#?";
if(Args.all) flags |= CHECKXFLAG_ALL;
if(Args.save) flags |= CHECKXFLAG_SAVE;
if(Args.askpwd) flags |= CHECKXFLAG_ASKPWD;
if(Args.automount) flags |= CHECKXFLAG_AUTOMOUNT;
if(Args.printall) flags |= CHECKXFLAG_PRINTALL;
if(Args.printexec) flags |= CHECKXFLAG_PRINTEXEC;
if(Args.nodecrunch) flags |= CHECKXFLAG_NODECRUNCH;
if(Args.nounlink) flags |= CHECKXFLAG_NOUNLINK;
if(Args.nounarchive) flags |= CHECKXFLAG_NOUNARCHIVE;
if(Args.nountrack) flags |= CHECKXFLAG_NOUNTRACK;
if(Args.notrackcut) flags |= CHECKXFLAG_NOTRACKCUT;
if(Args.nostrip) flags |= CHECKXFLAG_NOSTRIP;
if(!Args.novirus)
{
if((xvsbase = (struct xvsBase *) OpenLibrary("xvs.library", 33)))
{
flags |= CHECKXFLAG_XVSLIB;
xvsBase = xvsbase;
}
}
if(!Args.nounarchive || !Args.nountrack)
{
if((xadmasterbase = (struct xadMasterBase *) OpenLibrary("xadmaster.library", 1)))
{
flags |= CHECKXFLAG_XADLIB;
xadMasterBase = xadmasterbase;
}
}
if(!Args.log || (log = Open(Args.log, MODE_READWRITE)))
{
struct FileData fd;
APTR win;
ULONG s1 = 0, s2 = 0, msecs;
struct IntuitionBase *intuitionbase;
win = task->pr_WindowPtr;
task->pr_WindowPtr = (APTR) -1;
/* prevent dos requests */
if(log)
SetFileSize(log, 0, OFFSET_BEGINNING);
memset(&fd, 0, sizeof(struct FileData));
fd.fd_Flags = flags;
fd.fd_LogFileFH = log;
if(!xvsbase)
{
Printf("Virus-Checking disabled!\n");
if(log)
FPrintf(log, "Virus-Checking disabled!\n");
}
if((intuitionbase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
{
ASSIGN_INT
CurrentTime(&s1, &msecs);
}
error = DoDirectoryScan(Args.from, Args.save, &fd);
task->pr_WindowPtr = win;
if(intuitionbase)
{
CurrentTime(&s2, &msecs);
s2 -= s1;
s1 = s2 / 60;
s2 %= 60;
msecs = s1 / 60;
s1 %= 60;
Printf("\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
if(log)
FPrintf(log, "\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
CloseLibrary((struct Library *) intuitionbase);
}
if(fd.fd_NumVirus)
{
Printf("The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
if(log)
FPrintf(log, "The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
}
if(log)
Close(log);
}
else if(Args.log)
Printf("Could not create logfile.\n");
if(xvsbase)
CloseLibrary((struct Library *) xvsbase);
if(xadmasterbase)
CloseLibrary((struct Library *) xadmasterbase);
FreeArgs(rda);
}
FreeDosObject(DOS_RDARGS, rda);
}
CloseLibrary((struct Library *) xfdmasterbase);
}
CloseLibrary((struct Library *) dosbase);
}
return (error ? RETURN_FAIL : RETURN_OK);
}
/* This scans a directory and calls DoFileOpen for every file. It
automatically creates SAVE destination directories when necessary. */
LONG DoDirectoryScan(STRPTR name, STRPTR sav, struct FileData *fd)
{
struct AnchorPath *APath;
LONG error = CHKXERR_SCANERR;
ULONG retval;
if(!(fd->fd_Flags & CHECKXFLAG_SAVE) || !sav ||
(fd->fd_SaveDirL = Lock(sav, SHARED_LOCK)))
{
if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
512, MEMF_PUBLIC|MEMF_CLEAR)))
{
fd->fd_Name = APath->ap_Buf;
APath->ap_Strlen = 256;
for(retval = MatchFirst(name, APath); !retval;
retval = MatchNext(APath))
{
if(APath->ap_Flags & APF_DIDDIR)
{
OpenParentDir(fd);
APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
}
else if(APath->ap_Info.fib_DirEntryType > 0)
{
if(fd->fd_Flags & CHECKXFLAG_ALL)
{
OpenNewDir(fd, APath->ap_Info.fib_FileName);
APath->ap_Flags |= APF_DODIR;
}
}
else
{
PrintCHKXErr(fd, DoFileOpen(fd));
fd->fd_Flags &= CHKXCALLFLAGS;
fd->fd_LinkNum = 0;
while(fd->fd_MemList)
FreeCrunchMemList(fd, fd->fd_MemList->cml_MemoryRegion);
}
if((fd->fd_Flags & CHECKXFLAG_SAVE) && !fd->fd_SaveDirL)
{
error = CHKXERR_OPENDIR; break;
}
if(CTRL_C)
{
error = CHKXERR_BREAK; break;
}
}
MatchEnd(APath);
if(retval == ERROR_NO_MORE_ENTRIES)
error = 0;
FreeMem(APath, sizeof(struct AnchorPath) + 512);
}
else
error = CHKXERR_NOMEMORY;
if(sav && fd->fd_SaveDirL)
UnLock(fd->fd_SaveDirL);
}
else
error = CHKXERR_OPENDIR;
return error;
}
/* Open a file and call DoGetVirus to scan */
LONG DoFileOpen(struct FileData *fd)
{
struct FileInfoBlock *fib;
LONG ret;
if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
{
ULONG fh;
if(fd->fd_ArchiveDepth) /* prevent scan errors */
SetProtection(fd->fd_Name, 0); /* set RWED bits */
if((fh = Open(fd->fd_Name, MODE_OLDFILE)))
{
if(ExamineFH(fh, fib))
{
APTR mem;
if(!fib->fib_Size)
ret = CHKXERR_EMPTY;
else if((mem = AllocMem(fib->fib_Size, MEMF_ANY)))
{
if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
ret = CHKXERR_READWRITE;
else if(!(ret = AddCrunchMemList(fd, mem, fib->fib_Size)))
{
if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && fib->fib_Size > 4
&& *((ULONG *)mem) == HUNK_HEADER))
PrintCHKXFile(fd);
ret = DoGetVirus(fd, mem, fib->fib_Size);
}
}
else
ret = CHKXERR_NOMEMORY;
}
else
ret = CHKXERR_EXAMINEERR;
Close(fh);
}
else
ret = CHKXERR_OPENERR;
FreeDosObject(DOS_FIB, fib);
}
else
ret = CHKXERR_NOMEMORY;
return ret;
}
/* for SAVE option: open parent directory and try to delete the directory
we leave. This only succeeds, when the directory is empty. */
ULONG OpenParentDir(struct FileData *fd)
{
ULONG g;
UBYTE name[300];
if((g = fd->fd_SaveDirL))
{
NameFromLock(g, name, 300);
fd->fd_SaveDirL = ParentDir(g);
UnLock(g);
DeleteFile(name);
}
else
return -1;
return fd->fd_SaveDirL;
}
/* Open a new subdirectory for SAVE option */
ULONG OpenNewDir(struct FileData *fd, STRPTR name)
{
ULONG g;
if(fd->fd_SaveDirL)
{
g = CurrentDir(fd->fd_SaveDirL);
if(!(fd->fd_SaveDirL = Lock(name, SHARED_LOCK)))
if((fd->fd_SaveDirL = CreateDir(name)))
ChangeMode(CHANGE_LOCK, fd->fd_SaveDirL, SHARED_LOCK);
UnLock(CurrentDir(g));
}
else
return -1;
return fd->fd_SaveDirL;
}
void DoMount(ULONG deep, ULONG hd)
{
BPTR fh, infh;
UBYTE buf[50], buf2[60];
sprintf(buf, "T:CheckMountList_%08lx_%03ld", FindTask(0), deep);
if((fh = Open(buf, MODE_NEWFILE)))
{
FPrintf(fh,
"R%lc%ld:\n"
"\tDevice\t\t= ramdrive.device\n"
"\tUnit\t\t= %3ld\n"
"\tSurfaces\t= 2\n"
"\tBlocksPerTrack\t= %ld\n"
"\tReserved\t= 2\n"
"\tInterleave\t= 0\n"
"\tLowCyl\t\t= 0\n"
"\tHighCyl\t\t= 79\n"
"\tBootPri\t\t= -10\n"
"\tBuffers\t\t= 5\n"
"\tBufMemType\t= 1\n#\n", hd ? 'H' : 'D', deep, (hd ? 50 : 10) + deep,
hd ? 22 : 11);
Close(fh);
sprintf(buf2, "Mount R%lc%ld: FROM %s", hd ? 'H' : 'D', deep, buf);
/* I could do this myself, but I don't know, if it is the correct
method, so I use Mount command. */
if((infh = Open("NIL:", MODE_OLDFILE)))
{
if((fh = Open("NIL:", MODE_NEWFILE)))
{
SystemTags(buf2, SYS_Input, infh, SYS_Output, fh, TAG_DONE);
Close(fh);
}
Close(infh);
}
DeleteFile(buf);
}
}
/* Try to get RDx: disk and initialize it. */
BPTR GetRad(struct FileData *fd, STRPTR rname)
{
UBYTE name[20];
sprintf(name, NAME "%03ld", fd->fd_ArchiveDepth);
if(Inhibit(rname, 1))
{
Format(rname, name, ID_DOS_DISK);
Inhibit(rname, 0);
return Lock(rname, SHARED_LOCK);
}
else
{
LONG i, m = 0;
UBYTE name2[20];
struct DosList *dosl;
if((dosl = LockDosList(LDF_DEVICES|LDF_READ)))
{
i = strlen(rname);
name2[--i] = 0;
while(i--)
name2[i] = rname[i];
dosl = FindDosEntry(dosl, name2, LDF_DEVICES);
UnLockDosList(LDF_DEVICES|LDF_READ);
if(!dosl && (fd->fd_Flags & CHECKXFLAG_AUTOMOUNT))
{
DoMount(fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
fd->fd_HDDepth : fd->fd_DDDepth, fd->fd_Flags &
CHECKXFLAG_HIGHDENSITY);
m = 1;
}
if(dosl || m)
{
for(i = 0; i < 50; ++i)
{
if(Inhibit(rname, 1))
{
Format(rname, name, ID_DOS_DISK);
Inhibit(rname, 0);
return Lock(rname, SHARED_LOCK);
}
Delay(10);
}
/* clear flag if mount failed */
if(m)
fd->fd_Flags &= ~CHECKXFLAG_AUTOMOUNT;
}
}
}
return 0;
}
LONG DoGetVirus(struct FileData *fd, APTR buffer, ULONG buflength)
{
if(!buflength) /* restarted with empty file */
return CHKXERR_EMPTY;
if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
{
APTR mem;
if((mem = AllocMem(buflength, MEMF_ANY)))
{
struct xvsFileInfo *fi;
if((fi = (struct xvsFileInfo *) xvsAllocObject(XVSOBJ_FILEINFO)))
{
ULONG i;
/* xvs may modify the buffer! */
CopyMem(buffer, mem, buflength);
fi->xvsfi_File = mem;
fi->xvsfi_FileLen = buflength;
i = xvsCheckFile(fi);
if(i == XVSFT_DATAVIRUS)
{
PrintCHKXTxt(fd, "Data-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
else if(i == XVSFT_FILEVIRUS)
{
PrintCHKXTxt(fd, "File-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
else if(i == XVSFT_LINKVIRUS)
{
PrintCHKXTxt(fd, "Link-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
xvsFreeObject(fi);
}
else
PrintCHKXErr(fd, CHKXERR_NOVIRUS);
FreeMem(mem, buflength);
}
else
PrintCHKXErr(fd, CHKXERR_NOVIRUS);
}
return DoFileUnArchive(fd, buffer, buflength);
}
/****************************************************************************/
/**** old Archive stuff, should become obsolete *****/
/****************************************************************************/
#define ARCTYPE_LHA 1
#define ARCTYPE_ZIP 2
#define ARCTYPE_ZOO 3
#define ARCTYPE_LHA_SFX 4
#define ARCTYPE_ARC 5
#define CHECKXFLAG_ARCCOPY (1<<30)
#define CHECKXFLAG_DIRCHANGE (1<<31)
LONG DoArcNameCheck(struct UnArcData *, STRPTR, ULONG, ULONG,
struct FileData *);
LONG DeleteAll(STRPTR);
struct UnArcData { /* This is allocated to save stack space */
STRPTR uad_ArcName;
UBYTE uad_DestDir[30];
UBYTE uad_DoDestDir[30];
UBYTE uad_CopyArcName[30];
UBYTE uad_Command[200];
};
/* Test if we need to copy the archive to a temporary file. This is
necessary, because most archivers are not able to handle archives
correctly, when there are pattern characters in the path or archive
name. Also they fail, when the archive name has an incorrect extension.
For Archivers like Zoo and Arc, which dearchive always to current
directory, we need to copy always, as the arcname must have an absolute
path, which is not guarranteed for argument path name, as this may be
relative to current directory.
--> except we are already in a decrunched archive, as here the name is
garanted to be absolute, e.g. start with ':'.
Archives which are crunched with an alien cruncher or are linked must be
copied as well. (If this really exists ???)
In these cases the archive file is copied with a correct filename and
extension, so the archiver works well.
Problem: This needs mem (or disk space when T: is assigned to hard
disk).
*/
LONG DoArcNameCheck(struct UnArcData *uad, STRPTR mem, ULONG buflength,
ULONG arc, struct FileData *fd)
{
STRPTR p;
LONG err = 0;
for(p = uad->uad_ArcName; *p; ++p)
{
if(*p == '#' || *p == '(' || *p == ')' || *p == '[' || *p == ']'
|| *p == '*' || *p == '~' || *p == '#' || *p == '?' || *p == '|')
fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
}
if((fd->fd_Flags & (CHECKXFLAG_CRUNCHED|CHECKXFLAG_LINKED|CHECKXFLAG_FILEARCHIVED)) ||
((fd->fd_Flags & CHECKXFLAG_DIRCHANGE) && !fd->fd_ArchiveDepth))
fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
else if(!(fd->fd_Flags & CHECKXFLAG_ARCCOPY))
{
if((p -= 4) <= uad->uad_ArcName) /* position of extension */
p = uad->uad_ArcName+1; /* at least one char as name is needed */
switch(arc)
{
case ARCTYPE_LHA:
if(stricmp(p, ".lha") && stricmp(p, ".lzh"))
fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
break;
case ARCTYPE_ZIP:
if(stricmp(p, ".zip")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
break;
case ARCTYPE_LHA_SFX:
if(stricmp(p, ".run")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
break;
case ARCTYPE_ARC:
if(stricmp(p, ".arc")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
break;
case ARCTYPE_ZOO:
if(stricmp(p, ".zoo")) fd->fd_Flags |= CHECKXFLAG_ARCCOPY;
break;
}
}
if(fd->fd_Flags & CHECKXFLAG_ARCCOPY)
{
ULONG d;
switch(arc)
{
case ARCTYPE_LHA:
p = ".lha"; break;
case ARCTYPE_ZIP:
p = ".zip"; break;
case ARCTYPE_ZOO:
p = ".zoo"; break;
case ARCTYPE_LHA_SFX:
p = ".run"; break;
case ARCTYPE_ARC:
p = ".arc"; break;
}
sprintf(uad->uad_CopyArcName, "T:CheckArc_%08lx_%03ld%s", FindTask(0),
fd->fd_ArchiveDepth, p);
uad->uad_ArcName = uad->uad_CopyArcName;
if((d = Open(uad->uad_ArcName, MODE_NEWFILE)))
{
if(Write(d, mem, buflength) != buflength)
err = CHKXERR_READWRITE;
Close(d);
}
else
err = CHKXERR_OPENERR;
}
return err;
}
/* Tests if a file is an archive. When yes, the archive is unarchived and
DoDirectoryScan is called for the result files. Else DoFileUnLink is
called.
*/
LONG DoFileUnArchiveOld(struct FileData *fd, APTR buffer, ULONG buflength)
{
ULONG arc = 0;
STRPTR mem = (STRPTR) buffer;
LONG err = 0;
if(buflength > 7 && mem[2] == '-' && mem[3] == 'l' && mem[4] == 'h'
&& mem[6] == '-')
{ /* This is an LhA-File */
arc = ARCTYPE_LHA;
PrintCHKXTxt(fd, "LhA (ARCHIVE)");
}
else if(buflength > 4 && mem[0] == 'P' && mem[1] == 'K' && mem[2] == 3
&& mem[3] == 4)
{
arc = ARCTYPE_ZIP;
PrintCHKXTxt(fd, "Zip (ARCHIVE)");
}
else if(buflength > 4 && mem[0] == 'Z' && mem[1] == 'O' && mem[2] == 'O'
&& mem[3] == ' ' && mem[5] == '.')
{
arc = ARCTYPE_ZOO;
fd->fd_Flags |= CHECKXFLAG_DIRCHANGE;
PrintCHKXTxt(fd, "ZOO (ARCHIVE)");
}
else if(buflength > 4 && mem[0x2C] == 'S' && mem[0x2D] == 'F' &&
mem[0x2E] == 'X' && mem[0x2F] == '!' && *((ULONG *)mem) == 0x3F3)
{
arc = ARCTYPE_LHA_SFX;
PrintCHKXTxt(fd, "LhA SFX (ARCHIVE)");
}
else if(buflength > 2 && mem[0] == 0x1A && mem[1] && mem[1] < 9)
{ /* This detection is very unsecure !!! */
arc = ARCTYPE_ARC;
fd->fd_Flags |= CHECKXFLAG_DIRCHANGE;
PrintCHKXTxt(fd, "Arc (ARCHIVE)");
}
if(arc)
{
if(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE))
{
struct UnArcData *uad;
if((uad = (struct UnArcData *) AllocMem(sizeof(struct UnArcData),
MEMF_ANY)))
{ /* AllocMem to prevent stack overflow */
uad->uad_ArcName = fd->fd_Name;
err = DoArcNameCheck(uad, mem, buflength, arc, fd);
FreeCrunchMemList(fd, mem);
if(!err && !OpenNewDir(fd, FilePart(fd->fd_Name)))
err = CHKXERR_OPENERR;
if(!err)
{
BPTR destdir, storedir = 0;
sprintf(uad->uad_DestDir, "T:CheckX_%08lx_%03ld",
FindTask(0), fd->fd_ArchiveDepth);
sprintf(uad->uad_DoDestDir, "T:CheckX_%08lx_%03ld/#?",
FindTask(0), fd->fd_ArchiveDepth);
if((destdir = CreateDir(uad->uad_DestDir)))
{
ULONG infh;
ChangeMode(CHANGE_LOCK, destdir, SHARED_LOCK);
if(fd->fd_Flags & CHECKXFLAG_DIRCHANGE)
storedir = CurrentDir(destdir);
switch(arc)
{
case ARCTYPE_LHA: case ARCTYPE_LHA_SFX:
sprintf(uad->uad_Command, "Lha -IMmq x \"%s\" %s/",
uad->uad_ArcName, uad->uad_DestDir);
break;
case ARCTYPE_ZIP:
sprintf(uad->uad_Command, "UnZip \"%s\" -d %s/",
uad->uad_ArcName, uad->uad_DestDir);
break;
case ARCTYPE_ZOO:
sprintf(uad->uad_Command, "Zoo x//qqq \"%s\"",
uad->uad_ArcName);
break;
case ARCTYPE_ARC:
sprintf(uad->uad_Command, "Arc xwn \"%s\"",
uad->uad_ArcName);
break;
}
err = CHKXERR_RESOURCE;
if((infh = Open("NIL:", MODE_OLDFILE)))
{
ULONG outfh;
if((outfh = Open("NIL:", MODE_NEWFILE)))
{
ULONG i;
if(!(i = SystemTags(uad->uad_Command, SYS_Input, infh,
SYS_Output, outfh, TAG_DONE)))
err = 0;
else if(i != 10 || IoErr() != 205)
{
/* special error handling, gets later removed with this function */
PrintCHKXTxt(fd, "CheckX-Error 20: archiver returned error code");
err = 0;
}
Close(outfh);
}
Close(infh);
}
}
else
err = CHKXERR_OPENDIR;
if(fd->fd_Flags & CHECKXFLAG_ARCCOPY)
{ /* save some memory */
fd->fd_Flags &= ~CHECKXFLAG_ARCCOPY;
DeleteFile(uad->uad_ArcName);
}
if(destdir)
{
if(!err)
{
struct FileData fdp;
CopyMem(fd, &fdp, sizeof(struct FileData));
fdp.fd_Flags = (fdp.fd_Flags&CHKXCALLFLAGS)|CHECKXFLAG_ALL;
++fdp.fd_ArchiveDepth;
++fdp.fd_RecurseDepth;
fdp.fd_MemList = 0;
err = DoDirectoryScan(uad->uad_DoDestDir, 0, &fdp);
fd->fd_SaveDirL = fdp.fd_SaveDirL;
fd->fd_NumVirus = fdp.fd_NumVirus;
}
if(fd->fd_Flags & CHECKXFLAG_DIRCHANGE)
CurrentDir(storedir);
UnLock(destdir);
DeleteAll(uad->uad_DestDir);
}
if(!OpenParentDir(fd))
err = CHKXERR_OPENDIR;
}
if(fd->fd_Flags & CHECKXFLAG_ARCCOPY)
DeleteFile(uad->uad_ArcName);
FreeMem(uad, sizeof(struct UnArcData));
}
else
err = CHKXERR_NOMEMORY;
}
}
else
err = DoFileUnLink(fd, buffer, buflength);
return err;
}
/* This deletes a temporary directory and all files in it.
It returns 0 on error and gets name of directory to delete.
*/
LONG DeleteAll(STRPTR name)
{
LONG retval;
struct AnchorPath *APath;
STRPTR fname;
if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
512, MEMF_PUBLIC|MEMF_CLEAR)))
{
APath->ap_Strlen = 256;
fname = (STRPTR) APath->ap_Buf + 256;
for(retval = MatchFirst(name, APath); !retval; retval = MatchNext(APath))
{
if(*fname)
{
SetProtection(fname, 0); /* set RWED bits */
DeleteFile(fname);
}
CopyMem(APath->ap_Buf, fname, 256);
if(APath->ap_Flags & APF_DIDDIR)
APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
else if(APath->ap_Info.fib_DirEntryType > 0) /* a directory */
{
APath->ap_Flags |= APF_DODIR; *fname = 0;
}
}
MatchEnd(APath);
FreeMem(APath, sizeof(struct AnchorPath) + 512);
}
return DeleteFile(name); /* when this returns error, then any of the
above functions may have failed --> directory not empty. */
}
LONG CheckBoot(struct FileData *fd, STRPTR drivename)
{
LONG err = CHKXERR_NOBOOTVIRUS;
if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
{
struct DosList *dsl;
if((dsl = LockDosList(LDF_DEVICES|LDF_READ)))
{
if((dsl = FindDosEntry(dsl, drivename, LDF_DEVICES)))
{
struct FileSysStartupMsg *fssm;
fssm = (struct FileSysStartupMsg *) BADDR(dsl->dol_misc.dol_handler.dol_Startup);
if((LONG) fssm > 200)
{
struct DosEnvec *denv;
denv = ((struct DosEnvec *) BADDR(fssm->fssm_Environ));
/* test if the entry is a correct fssm -> check for valid data */
if(denv && denv->de_TableSize < 64 && !(denv->de_SizeBlock &
0x127) && (denv->de_LowCyl <= denv->de_HighCyl))
{
struct MsgPort *mp;
if((mp = CreateMsgPort()))
{
struct IOStdReq *req;
if((req = (struct IOStdReq *) CreateIORequest(mp, sizeof(struct IOStdReq))))
{
if(!OpenDevice(((STRPTR)(fssm->fssm_Device<<2))+1, fssm->fssm_Unit, (struct IORequest *)req, 0))
{
APTR mem;
if((mem = AllocMem(1024, MEMF_ANY)))
{
req->io_Command = CMD_READ;
req->io_Length = 1024;
req->io_Data = mem;
/* req->io_Offset = 0 */;
if(!DoIO((struct IORequest *)req))
{
struct xvsBootInfo *bi;
if((bi = (struct xvsBootInfo *) xvsAllocObject(XVSOBJ_BOOTINFO)))
{
bi->xvsbi_Bootblock = mem;
err = 0;
if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
{
PrintCHKXTxt(fd, "Boot-Virus '%s'", bi->xvsbi_Name);
++fd->fd_NumVirus;
}
xvsFreeObject(bi);
}
}
FreeMem(mem, 1024);
}
CloseDevice((struct IORequest *) req);
}
DeleteIORequest(req);
}
DeleteMsgPort(mp);
}
}
}
}
UnLockDosList(LDF_DEVICES|LDF_READ);
}
}
else
err = 0;
return err;
}
/****************************************************************************/
/* Tests if a file is an archive. When yes, the archive is unarchived and
DoDirectoryScan is called for the result files. Else DoFileUnLink is
called.
*/
LONG DoFileUnArchive(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG err = 0;
if(fd->fd_Flags & CHECKXFLAG_XADLIB)
{
struct xadArchiveInfo *ai;
if((ai = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
{
if(!xadGetInfo(ai, XAD_INMEMORY, buffer, XAD_INSIZE, buflength,
TAG_DONE))
{
STRPTR arcname;
arcname = fd->fd_Name;
if(ai->xai_Flags & XADAIF_FILECORRUPT)
PrintCHKXTxt(fd, "%s (ARCHIVE, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
else
PrintCHKXTxt(fd, "%s (ARCHIVE)", ai->xai_Client->xc_ArchiverName);
if(!(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo ||
!(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo))
err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
err = CHKXERR_OPENERR;
else
{
if(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo)
{
struct xadFileInfo *fi;
fi = ai->xai_FileInfo;
while(!CTRL_C && fi)
{
APTR dest;
if(!(fi->xfi_Flags & (XADFIF_DIRECTORY|XADFIF_LINK)))
{
ULONG flags;
flags = fd->fd_Flags;
fd->fd_Flags &= ~CHECKXFLAG_NAMEPRINTED;
fd->fd_Flags |= CHECKXFLAG_FILEARCHIVED;
fd->fd_Name = fi->xfi_FileName;
fd->fd_RecurseDepth++;
fd->fd_ArchiveDepth++;
if(!fi->xfi_Size)
err = CHKXERR_EMPTY;
else if((dest = AllocMem(fi->xfi_Size, MEMF_PUBLIC)))
{
if(!(err = AddCrunchMemList(fd, dest, fi->xfi_Size)))
{
if((err = xadFileUnArc(ai, XAD_OUTMEMORY, dest, XAD_OUTSIZE,
fi->xfi_Size, XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE)))
err += XADERR_OFFSET;
else
{
if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && fi->xfi_Size > 4
&& *((ULONG *)dest) == HUNK_HEADER))
PrintCHKXFile(fd);
err = DoGetVirus(fd, dest, fi->xfi_Size);
}
FreeCrunchMemList(fd, dest);
}
else
FreeMem(dest, fi->xfi_Size);
}
else
err = CHKXERR_NOMEMORY;
if(err)
{
PrintCHKXErr(fd, err);
err = 0;
}
--fd->fd_RecurseDepth;
--fd->fd_ArchiveDepth;
fd->fd_Flags = flags;
}
fi = fi->xfi_Next;
}
}
if(!(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo)
{
struct DiskInfoData {
UBYTE name[10];
UBYTE buf[50];
BPTR destdir;
ULONG geom;
} *d;
/* reduce stacksize, as we have a recursive program */
if((d = AllocMem(sizeof(struct DiskInfoData), MEMF_PUBLIC)))
{
struct xadDiskInfo *di;
di = ai->xai_DiskInfo;
while(!CTRL_C && di)
{
if(di->xdi_SectorSize != 512 || (di->xdi_TrackSectors != 11 &&
di->xdi_TrackSectors != 22) || (!(di->xdi_Flags & XADDIF_NOHEADS) &&
di->xdi_Heads != 2) || (!(di->xdi_Flags & XADDIF_NOCYLINDERS) &&
di->xdi_Cylinders != 80))
{
sprintf(d->buf, "-disk image %ld (unsupported geometry)", di->xdi_EntryNumber);
d->geom = 1;
}
else
{
d->geom = 0;
if(di->xdi_TrackSectors == 11)
sprintf(d->name, "RD%ld:", fd->fd_DDDepth);
else
{
fd->fd_Flags |= CHECKXFLAG_HIGHDENSITY;
sprintf(d->name, "RH%ld:", fd->fd_HDDepth);
}
if(!(di->xdi_Flags & (XADDIF_NOHIGHCYL|XADDIF_NOLOWCYL)) &&
(di->xdi_LowCyl || di->xdi_HighCyl != 79))
sprintf(d->buf, "-disk image %ld (%s, %ld to %ld)",
di->xdi_EntryNumber, fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
"HD" : "DD", di->xdi_LowCyl, di->xdi_HighCyl);
else
sprintf(d->buf, "-disk image %ld (%s)",
di->xdi_EntryNumber, fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
"HD" : "DD");
}
fd->fd_Name = d->buf;
PrintCHKXFile(fd);
if(di->xdi_TextInfo)
{
struct xadTextInfo *ti;
ULONG flags, i = 1;
for(ti = di->xdi_TextInfo; ti; ti = ti->xti_Next)
{
if(ti->xti_Size && ti->xti_Text)
{
flags = fd->fd_Flags;
fd->fd_Flags &= ~CHECKXFLAG_NAMEPRINTED;
fd->fd_Flags |= CHECKXFLAG_NOFREEMEM|CHECKXFLAG_DISKARCHIVED;
fd->fd_RecurseDepth++;
sprintf(d->buf, "--infotext %ld (size %ld)", i, ti->xti_Size);
if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && ti->xti_Size > 4
&& *((ULONG *)(ti->xti_Text)) == HUNK_HEADER))
PrintCHKXFile(fd);
PrintCHKXErr(fd, DoGetVirus(fd, ti->xti_Text, ti->xti_Size));
--fd->fd_RecurseDepth;
fd->fd_Flags = flags;
}
++i;
}
}
if(!d->geom)
{
if((di->xdi_LowCyl == 0 && di->xdi_HighCyl == 79) ||
!(fd->fd_Flags & CHECKXFLAG_NOTRACKCUT) ||
(di->xdi_Flags & XADDIF_NOCYLINDERS))
{
if((d->destdir = GetRad(fd, d->name)))
{
struct xadDeviceInfo *dvi;
UnLock(d->destdir);
if((dvi = (struct xadDeviceInfo *)
xadAllocObjectA(XADOBJ_DEVICEINFO, 0)))
{
d->name[strlen(d->name)-1] = 0;
dvi->xdi_DOSName = d->name;
if(!(err = xadDiskUnArc(ai, XAD_OUTDEVICE, dvi,
XAD_ENTRYNUMBER, di->xdi_EntryNumber, XAD_VERIFY,
TRUE, TAG_DONE)) && !di->xdi_LowCyl)
PrintCHKXErr(fd, CheckBoot(fd, d->name));
xadFreeObjectA(dvi, 0);
d->name[strlen(d->name)] = ':';
}
else
err = CHKXERR_NOMEMORY;
if(err)
{
PrintCHKXErr(fd, XADERR_OFFSET+err); err = 0;
}
else if(!(d->destdir = Lock(d->name, SHARED_LOCK)))
PrintCHKXErr(fd, CHKXERR_NODOS);
else
{
struct FileData fdp;
CopyMem(fd, &fdp, sizeof(struct FileData));
fdp.fd_Flags = (fdp.fd_Flags&CHKXCALLFLAGS)|CHECKXFLAG_ALL;
fdp.fd_MemList = 0;
fdp.fd_ArchiveDepth++;
fdp.fd_RecurseDepth++;
if(fd->fd_Flags & CHECKXFLAG_HIGHDENSITY)
++fdp.fd_HDDepth;
else
++fdp.fd_DDDepth;
PrintCHKXErr(fd, DoDirectoryScan(d->name, 0, &fdp));
fd->fd_SaveDirL = fdp.fd_SaveDirL;
fd->fd_NumVirus = fdp.fd_NumVirus;
UnLock(d->destdir);
}
}
else
PrintCHKXErr(fd, CHKXERR_NORAD);
}
}
fd->fd_Flags &= ~CHECKXFLAG_HIGHDENSITY;
di = di->xdi_Next;
} /* while */
FreeMem(d, sizeof(struct DiskInfoData));
} /* AllocMem DiskInfoData */
else
err = CHKXERR_NOMEMORY;
} /* is there is disk entry? */
if(!OpenParentDir(fd))
err = CHKXERR_OPENDIR;
}
fd->fd_Name = arcname;
}
else
err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
xadFreeObjectA(ai, 0);
}
else
err = CHKXERR_NOMEMORY;
}
else
err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
return err;
}
/* Tries to unlink a file. When the file was linked, we call DoGetVirus
for the two parts to check if they may be archives, else we call
DoFileUnCrunch.
*/
LONG DoFileUnLink(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = CHKXERR_NOMEMORY;
struct xfdLinkerInfo *xli;
if((xli = (struct xfdLinkerInfo *) xfdAllocObject(XFDOBJ_LINKERINFO)))
{
xli->xfdli_Buffer = buffer;
xli->xfdli_BufLen = buflength;
if(xfdRecogLinker(xli))
{
PrintCHKXTxt(fd, xli->xfdli_LinkerName);
if(fd->fd_Flags & CHECKXFLAG_NOUNLINK)
ret = DoFileUnCrunch(fd, buffer, buflength);
else if(xfdUnlink(xli))
{
ULONG flags;
fd->fd_Flags |= CHECKXFLAG_LINKED;
++fd->fd_RecurseDepth;
++fd->fd_LinkNum;
flags = fd->fd_Flags;
fd->fd_Flags |= CHECKXFLAG_NOFREEMEM;
PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save1,
xli->xfdli_SaveLen1));
fd->fd_Flags = flags; /* CHECKXFLAG_NOFREEMEM is cleared */
PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save2,
xli->xfdli_SaveLen2));
ret = 0;
--fd->fd_RecurseDepth;
}
else
ret = XFDERR_OFFSET + xli->xfdli_Error;
}
else
ret = DoFileUnCrunch(fd, buffer, buflength);
xfdFreeObject(xli);
}
return ret;
}
/* Tries to decrunch a file. When it is crunched, we decrunch it and call
DoGetVirus to start the loop again. Else we call unstripping.
*/
LONG DoFileUnCrunch(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = CHKXERR_NOMEMORY;
struct xfdBufferInfo *xbi;
if((xbi = (struct xfdBufferInfo *) xfdAllocObject(XFDOBJ_BUFFERINFO)))
{
xbi->xfdbi_SourceBuffer = buffer;
xbi->xfdbi_SourceBufLen = buflength;
xbi->xfdbi_Flags = XFDFF_RECOGEXTERN;
if(xfdRecogBuffer(xbi))
{
struct Library *xpkbase;
STRPTR buf = 0;
ULONG buflen = 0;
PrintCHKXTxt(fd, xbi->xfdbi_PackerFlags & XFDPFF_ADDR ? "%s (ADDRESS)" :
"%s", xbi->xfdbi_PackerName);
if(fd->fd_Flags & CHECKXFLAG_ASKPWD && (xpkbase =
OpenLibrary(XPKNAME, 4)))
{
ASSIGN_XPK
if(xbi->xfdbi_PackerFlags & XFDPFF_PASSWORD)
{
buflen = (xbi->xfdbi_MaxSpecialLen == 0xFFFF) ? 256 :
xbi->xfdbi_MaxSpecialLen;
if((buf = (STRPTR) AllocMem(buflen, MEMF_ANY|MEMF_CLEAR)))
{
if(!XpkPassRequestTags(XPK_PasswordBuf, buf,
XPK_PassBufSize, buflen, TAG_DONE))
xbi->xfdbi_Special = buf;
}
}
else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY16)
{
if(!XpkPassRequestTags(XPK_Key16BitPtr, &buflen, TAG_DONE))
xbi->xfdbi_Special = &buflen;
}
else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY32)
{
if(!XpkPassRequestTags(XPK_Key32BitPtr, &buflen, TAG_DONE))
xbi->xfdbi_Special = &buflen;
}
CloseLibrary(xpkbase);
}
if(fd->fd_Flags & CHECKXFLAG_NODECRUNCH)
ret = DoFileStrip(fd, buffer, buflength);
else if(xfdDecrunchBuffer(xbi))
{
if((xbi->xfdbi_PackerFlags & XFDPFF_ADDR) &&
!(fd->fd_Flags & CHECKXFLAG_ADDRESS))
{
fd->fd_Flags |= CHECKXFLAG_ADDRESS;
PrintCHKXErr(fd, SaveUncrFile(fd, buffer, buflength));
}
fd->fd_Flags |= CHECKXFLAG_CRUNCHED;
FreeCrunchMemList(fd, buffer);
++fd->fd_RecurseDepth;
if(!(ret = AddCrunchMemList(fd, xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufLen)))
{
PrintCHKXErr(fd, DoGetVirus(fd, xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufSaveLen));
}
--fd->fd_RecurseDepth;
}
else
ret = XFDERR_OFFSET + xbi->xfdbi_Error;
if(buf)
FreeMem(buf, buflen);
}
else
ret = DoFileStrip(fd, buffer, buflength);
xfdFreeObject(xbi);
}
return ret;
}
/* Tries to strip useless hunks in a file. When there are some, we remove
them and call DoGetVirus to start the loop again. Else we finish.
When either unlinking or uncrunching happend in before loops, we may
save the file when there was SAVE option.
*/
LONG DoFileStrip(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = 0;
ULONG reslength = buflength;
if(*((ULONG *) buffer) == 0x000003F3 && !(fd->fd_Flags &
CHECKXFLAG_NOSTRIP))
xfdStripHunks(buffer, buflength, &reslength,
XFDSHF_NAME|XFDSHF_SYMBOL|XFDSHF_DEBUG);
/* errors are not interpreted */
if(buflength > reslength)
{
fd->fd_Flags |= CHECKXFLAG_STRIPPED;
PrintCHKXTxt(fd, "%ld bytes stripped", buflength-reslength);
ret = DoGetVirus(fd, buffer, reslength);
}
else if(!(fd->fd_Flags & CHECKXFLAG_ADDRESS))
ret = SaveUncrFile(fd, buffer, buflength);
FreeCrunchMemList(fd, buffer);
return ret;
}
/* Print file name */
void PrintCHKXFile(struct FileData *fd)
{
STRPTR name = fd->fd_Name;
UBYTE i;
if(fd->fd_ArchiveDepth) /* skip that ugly T:CheckX.. or RD?: */
{
if(*name == 'R' && (name[1] == 'D' || name[1] == 'H'))
{
while(*name != ':')
++name;
++name;
}
else if(*name == 'T' && name[1] == ':') /* becomes obsolete with Archive stuff remove */
{
while(*name != '/')
++name;
++name;
}
}
if(fd->fd_LogFileFH)
{
for(i = 0; i < fd->fd_ArchiveDepth; ++i)
FPutC(fd->fd_LogFileFH, '*');
FPrintf(fd->fd_LogFileFH, "%s\n", name);
}
for(i = 0; i < fd->fd_ArchiveDepth; ++i)
FPutC(Output(), '*');
Printf("%s\n", name);
fd->fd_Flags |= CHECKXFLAG_NAMEPRINTED;
}
/* Print Error - Error 100 and up are CheckX special errors. */
void PrintCHKXErr(struct FileData *fd, LONG err)
{
if(err)
{
STRPTR txt = 0, txt2;
if(err > XFDERR_OFFSET)
{
txt2 = "XFD-Error %ld: %s";
err -= XFDERR_OFFSET;
txt = xfdGetErrorText(err);
}
else if(err > XADERR_OFFSET)
{
txt2 = "XAD-Error %ld: %s";
err -= XADERR_OFFSET;
txt = xadGetErrorText(err);
}
else
{
txt2 = "CheckX-Error %ld: %s";
switch(err)
{
case CHKXERR_NOMEMORY: txt = "not enough memory"; break;
case CHKXERR_EXAMINEERR: txt = "examining failed"; break;
case CHKXERR_OPENERR: txt = "opening file failed"; break;
case CHKXERR_READWRITE: txt = "read or write failed"; break;
case CHKXERR_SCANERR: txt = "directory scan failed"; break;
case CHKXERR_BREAK: txt = "user break"; break;
case CHKXERR_OPENDIR: txt = "opening directory failed"; break;
case CHKXERR_NORAD: txt = "accessing ramdrive failed"; break;
case CHKXERR_NODOS: txt = "not an Amiga DOS disk"; break;
case CHKXERR_RESOURCE: txt = "needed resource not available"; break;
case CHKXERR_NOVIRUS: txt = "could not check for virus"; break;
case CHKXERR_EMPTY: txt = "file is empty"; break;
case CHKXERR_NOBOOTVIRUS: txt = "could not check for bootblock virus"; break;
}
}
PrintCHKXTxt(fd, txt2, err, txt);
}
}
/* Print type text */
void PrintCHKXTxt(struct FileData *fd, STRPTR txt, ...)
{
UBYTE i;
if(!(fd->fd_Flags & CHECKXFLAG_NAMEPRINTED))
PrintCHKXFile(fd);
if(fd->fd_LogFileFH)
{
for(i = 0; i <= fd->fd_RecurseDepth; ++i)
FPutC(fd->fd_LogFileFH, ' ');
VFPrintf(fd->fd_LogFileFH, txt, &txt+1);
FPutC(fd->fd_LogFileFH, '\n');
Flush(fd->fd_LogFileFH);
}
for(i = 0; i <= fd->fd_RecurseDepth; ++i)
FPutC(Output(), ' ');
VPrintf(txt, &txt+1);
FPutC(Output(), '\n');
}
/* Add memory to the memory list. */
LONG AddCrunchMemList(struct FileData *fd, APTR reg, ULONG size)
{
struct CrunchMemList *ml;
if((ml = (struct CrunchMemList *) AllocMem(sizeof(struct CrunchMemList),
MEMF_ANY)))
{
ml->cml_Next = fd->fd_MemList;
ml->cml_MemoryRegion = reg;
ml->cml_MemorySize = size;
fd->fd_MemList = ml;
}
else
{
FreeMem(reg, size);
return CHKXERR_NOMEMORY;
}
return 0;
}
/* Free memory from the memory list. */
void FreeCrunchMemList(struct FileData *fd, APTR reg)
{
struct CrunchMemList mc, *ml = &mc;
if(fd->fd_Flags & CHECKXFLAG_NOFREEMEM)
return;
for(mc.cml_Next = fd->fd_MemList; ml; ml = ml->cml_Next)
{
if(ml->cml_Next->cml_MemoryRegion == reg)
{
struct CrunchMemList *m;
m = ml->cml_Next;
ml->cml_Next = m->cml_Next;
FreeMem(m->cml_MemoryRegion, m->cml_MemorySize);
FreeMem(m, sizeof(struct CrunchMemList));
}
}
fd->fd_MemList = mc.cml_Next;
}
/* Save file, when SAVE option and file was crunched or linked. */
LONG SaveUncrFile(struct FileData *fd, APTR buf, ULONG size)
{
BPTR filefh, cd;
LONG ret = 0, i = 0;
UBYTE name[50];
UBYTE nbuf[256];
if(!(fd->fd_SaveDirL && (fd->fd_Flags & CHKXSAVEFLAGS)))
return 0;
sprintf(name, (fd->fd_LinkNum ? "%s.%ld" : "%s"), FilePart(fd->fd_Name),
fd->fd_LinkNum++);
cd = CurrentDir(fd->fd_SaveDirL);
while(!ret && name[i])
{
for(;name[i] && name[i] != '/'; ++i)
nbuf[i] = name[i];
if(name[i] == '/')
{
nbuf[i] = 0;
if((filefh = Lock(nbuf, SHARED_LOCK)))
UnLock(filefh);
else
{
if((filefh = CreateDir(nbuf)))
UnLock(filefh);
else
ret = CHKXERR_OPENERR;
}
nbuf[i] = name[i];
++i;
}
}
if(!ret)
{
if((filefh = Open(name, MODE_NEWFILE)))
{
if(Write(filefh, buf, size) != size)
ret = CHKXERR_READWRITE;
Close(filefh);
}
else
ret = CHKXERR_OPENERR;
}
CurrentDir(cd);
return ret;
}